<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <title>Porting MicroPython and wasp-os to Mynewt on PineTime Smart Watch (nRF52)</title>

    
    <!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
<meta property="og:title" 
    content="Porting MicroPython and wasp-os to Mynewt on PineTime Smart Watch (nRF52)" 
    data-rh="true">
<meta property="og:description" 
    content="Making wasp-os truly awesome with full multitasking, interoperable firmware updates and a common companion app" 
    data-rh="true">
<meta property="og:image" 
    content="https://lupyuen.github.io/images/micropython-title.jpg">
<meta property="og:type" 
    content="article" data-rh="true">
<!-- End scripts/articles/*-header.html -->
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
<link rel="stylesheet" type="text/css" href="../normalize.css">
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
<link rel="stylesheet" type="text/css" href="../dark.css">
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
<script src="../storage.js"></script><noscript>
<link rel="stylesheet" href="../noscript.css"></noscript>
<link rel="shortcut icon" href="../favicon.ico">
<style type="text/css">
    #crate-search {
        background-image: url("../down-arrow.svg");
    }
    a {
        color: #77d;
    }
</style>
<!-- End scripts/rustdoc-header.html -->


</head>
<body class="rustdoc">
    <!--[if lte IE 8]>
    <div class="warning">
        This old browser is unsupported and will most likely display funky
        things.
    </div>
    <![endif]-->

        <!-- Begin scripts/rustdoc-before.html: Pre-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->

    <!-- Begin Theme Picker -->
    <div class="theme-picker" style="left: 0"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg"
        width="18" alt="Pick another theme!"></button>
        <div id="theme-choices"></div>
    </div>
    <script src="../theme.js"></script>
    <!-- Theme Picker -->

    <!-- End scripts/rustdoc-before.html -->
    

    <h1 class="title">Porting MicroPython and wasp-os to Mynewt on PineTime Smart Watch (nRF52)</h1>
    <nav id="TOC"><ul>
<li><a href="#better-micropython-and-wasp-os-on-pinetime">1 Better MicroPython and wasp-os on PineTime</a><ul></ul></li>
<li><a href="#host-micropython-and-wasp-os-on-mynewt">2 Host MicroPython and wasp-os on Mynewt</a><ul></ul></li>
<li><a href="#hardware-abstraction-layer-for-pinetime">3 Hardware Abstraction Layer for PineTime</a><ul></ul></li>
<li><a href="#mynewt-port-for-micropython">4 Mynewt Port for MicroPython</a><ul>
<li><a href="#configuration">4.1 Configuration</a><ul></ul></li>
<li><a href="#peripheral-drivers-gpio-i2c-spi">4.2 Peripheral Drivers: GPIO, I2C, SPI</a><ul></ul></li>
<li><a href="#other-drivers">4.3 Other Drivers</a><ul></ul></li>
<li><a href="#start-micropython">4.4 Start MicroPython</a><ul></ul></li>
<li><a href="#reset-handler-vector-table-and-linker-script">4.5 Reset Handler, Vector Table and Linker Script</a><ul></ul></li></ul></li>
<li><a href="#gpio-driver">5 GPIO Driver</a><ul></ul></li>
<li><a href="#spi-driver">6 SPI Driver</a><ul></ul></li>
<li><a href="#i2c-driver">7 I2C Driver</a><ul></ul></li>
<li><a href="#heap-memory-in-micropython">8 Heap Memory in MicroPython</a><ul></ul></li>
<li><a href="#heap-memory-in-mynewt">9 Heap Memory in Mynewt</a><ul></ul></li>
<li><a href="#nimble-bluetooth-stack">10 NimBLE Bluetooth Stack</a><ul></ul></li>
<li><a href="#task-scheduling-micropython-vs-mynewt">11 Task Scheduling: MicroPython vs Mynewt</a><ul></ul></li>
<li><a href="#build-and-flash-mynewt--micropython-firmware">12 Build and Flash Mynewt + MicroPython Firmware</a><ul>
<li><a href="#install-build-tools">12.1 Install Build Tools</a><ul></ul></li>
<li><a href="#dowload-source-files">12.2 Dowload Source Files</a><ul></ul></li>
<li><a href="#build-mynewt-firmware">12.3 Build Mynewt Firmware</a><ul></ul></li>
<li><a href="#build-wasp-os-and-micropython">12.4 Build wasp-os and MicroPython</a><ul></ul></li>
<li><a href="#build-mynewt--micropython-firmware">12.5 Build Mynewt + MicroPython Firmware</a><ul></ul></li>
<li><a href="#select-the-openocd-interface-st-link-or-raspberry-pi-spi">12.6 Select the OpenOCD Interface: ST-Link or Raspberry Pi SPI</a><ul></ul></li>
<li><a href="#flash-mcuboot-bootloader">12.7 Flash MCUBoot Bootloader</a><ul></ul></li>
<li><a href="#flash-mynewt--micropython-firmware">12.8 Flash Mynewt + MicroPython Firmware</a><ul></ul></li></ul></li>
<li><a href="#debug-log">13 Debug Log</a><ul></ul></li>
<li><a href="#loose-ends">14 Loose Ends</a><ul></ul></li>
<li><a href="#whats-next">15 What's Next</a><ul></ul></li>
<li><a href="#further-reading">16 Further Reading</a><ul></ul></li></ul></nav><p><img src="https://lupyuen.github.io/images/micropython-title.jpg" alt="MicroPython and wasp-os hosted on Mynewt on PineTime Smart Watch. VSCode Debugger is shown on the monitor" /></p>
<p><em>MicroPython and wasp-os hosted on Mynewt on PineTime Smart Watch. VSCode Debugger is shown on the monitor</em></p>
<p><a href="https://wasp-os.readthedocs.io/en/latest/README.html"><strong>wasp-os</strong></a>, built with <a href="https://micropython.org/"><strong>MicroPython</strong></a>, is highly popular with folks coding <a href="https://wiki.pine64.org/index.php/PineTime"><strong>PineTime Smart Watch</strong></a> for the very first time...</p>
<p><em>Because there's no easier way to create a Watch App for PineTime!</em></p>
<p>Just write a simple Python script, upload it wirelessly to wasp-os and watch it run!</p>
<p>And if the script doesn't work right? Just connect over Bluetooth and troubleshoot live with the REPL (Read-Eval-Print Loop) command line!</p>
<p>Today wasp-os works great on Bare Metal (i.e. PineTime hardware). It doesn't require an embedded operating system, because the underlying MicroPython runtime serves as a bare-bones operating system.</p>
<p><img src="https://lupyuen.github.io/images/micropython-mynewt0.png" alt="MicroPython and wasp-os on PineTime" /></p>
<h1 id="better-micropython-and-wasp-os-on-pinetime" class="section-header"><a href="#better-micropython-and-wasp-os-on-pinetime">1 Better MicroPython and wasp-os on PineTime</a></h1>
<p><em>How shall we make wasp-os better?</em></p>
<p>I'm now coding these enhancements in MicroPython...</p>
<ol>
<li>
<p><strong>Easier Installation</strong></p>
<p>What if PineTime Owners can unbox their smart watches... And install wasp-os wirelessly through their phones? No more messy wiring to the SWD Port inside PineTime!</p>
<p>And we'll let PineTime Owners switch and test drive any operating system wirelessly: wasp-os, FreeRTOS, Mynewt, RIOT, Zephyr, ... Without opening their watches!</p>
<p>We're getting ready a <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot">Common Bootloader</a> and <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfu">Firmware Update mechanism</a> that will be preloaded by Pine64 into PineTime watches... Would be terrific to have wasp-os and MicroPython on board!</p>
<p>More about this in a while.</p>
</li>
<li>
<p><strong>PineTime Companion App for Android, iOS and PinePhone</strong></p>
<p>A common Companion App for PineTime that updates the firmware, uploads Watch Apps and lets you interact via the REPL command line... That works on Android, iOS and PinePhone!</p>
<p>If you have a Raspberry Pi, the Companion App will run too! (Using Pi's onboard Bluetooth hardware)</p>
<p><a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/flutter">We're creating the Companion App now</a>... And we hope to have wasp-os adopting the <a href="https://github.com/apache/mynewt-mcumgr">Simple Management Protocol</a> that's used by Mynewt, RIOT, FreeRTOS and Zephyr.</p>
<p>We have a solution for this... More about this later.</p>
</li>
<li>
<p><strong>Simpler Firmware Debugging with Raspberry Pi and VSCode</strong></p>
<p>For newbies who have mastered MicroPython programming on PineTime, perhaps they would like to dig deeper into the internals of wasp-os firmware, make some tweaks, experiment with the Bluetooth stack, ...</p>
<p>Let's make it easier for them to explore! Just connect a Raspberry Pi to PineTime's SWD Port (yep slightly messy) and step through the firmware code with the VSCode Debugger.</p>
<p>Or just study the helpful debugging messages that will be displayed in OpenOCD, thanks to the SWD Semihosting Console. </p>
<p>Check out this video of wasp-os and MicroPython debug messages displayed on the Semihosting Console with OpenOCD and VSCode...</p>
<ul>
<li>
<p><a href="https://youtu.be/_mhxvYG9Qos">Watch on YouTube</a></p>
</li>
<li>
<p><a href="https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v4.2.0/micropython-semihosting-rotated.mp4">Download the video</a></p>
</li>
</ul>
</li>
<li>
<p><strong>Preemptive Multitasking</strong></p>
<p>MicroPython comes with simple task management. Perhaps we should get ready to support Watch Apps that require full multitasking?</p>
<p>If we build a MicroPython Watch App that talks to other watches over Bluetooth Mesh... Surely we'll need some kind of background processing?</p>
</li>
<li>
<p><strong>Best Buddies with other Operating Systems</strong></p>
<p>PineTime feels like a rowdy playground sometimes... Kids (i.e. various PineTime Firmware) come and go as they please, messing up the sandbox (e.g. PineTime's SPI Flash) for the other players.</p>
<p>Can we turn PineTime into a safer, happier playground for all? </p>
<p>Adopting a common filesystem (like littlefs) with fixed parameters (SPI Flash location) may help.</p>
<p><img src="https://lupyuen.github.io/images/micropython-scratch.png" alt="PineTime Bootloader's Boot Graphic (stored in SPI Flash) unintentionally scratched (top left) by the firmware" /></p>
<p><em>PineTime Bootloader's Boot Graphic (stored in SPI Flash) unintentionally scratched (top left) by the firmware</em></p>
</li>
</ol>
<h1 id="host-micropython-and-wasp-os-on-mynewt" class="section-header"><a href="#host-micropython-and-wasp-os-on-mynewt">2 Host MicroPython and wasp-os on Mynewt</a></h1>
<p>To make wasp-os truly awesome with interoperable firmware updates (and a common companion app), we could add to MicroPython the following open source components...</p>
<ol>
<li>
<p><a href="https://github.com/apache/mynewt-nimble">NimBLE Bluetooth Networking Stack</a></p>
</li>
<li>
<p><a href="https://juullabs-oss.github.io/mcuboot/">MCUBoot Bootloader</a></p>
</li>
<li>
<p><a href="https://github.com/apache/mynewt-mcumgr">MCU Manager Library</a> for Simple Management Protocol</p>
</li>
<li>
<p>And a sophisticated Task Scheduler</p>
</li>
</ol>
<p><img src="https://lupyuen.github.io/images/micropython-mynewt1.png" alt="MicroPython and wasp-os without Mynewt" /></p>
<p><em>Looks daunting!</em></p>
<p>Or we could <strong>host wasp-os and MicroPython on Mynewt,</strong> which already includes NimBLE, MCUBoot, MCU Manager and <a href="https://mynewt.apache.org/latest/os/core_os/mynewt_os.html">Preemptive Multitasking</a>...</p>
<p><img src="https://lupyuen.github.io/images/micropython-mynewt2.png" alt="MicroPython and wasp-os hosted on Mynewt" /></p>
<p>That's the approach we'll explore. Hosting MicroPython on another operating system isn't new... It has been done with <a href="https://github.com/micropython/micropython/tree/master/ports/zephyr">Zephyr</a>, which is similar to Mynewt.</p>
<p><em>What could go wrong?</em></p>
<p>There are plenty of risks in running wasp-os and MicroPython on Mynewt instead of Bare Metal...</p>
<ol>
<li>
<p><strong>MicroPython is Dynamic, Mynewt is Not</strong></p>
<p>MicroPython allocates objects dynamically in <strong>Heap Memory.</strong> When Heap Memory runs low, the Garbage Collector sweeps the memory and reclaims space for new objects.</p>
<p>Traditional embedded operating systems are engineered to be highly predictable and less flexible. Objects live in <strong>Static Memory and Stack Memory,</strong> not in Heap Memory.</p>
<p><em>Embedded operating systems like Mynewt will get spooked by Dynamic Objects in MicroPython!</em></p>
<p>Heap Memory needs to be managed really carefully with Mynewt.</p>
</li>
<li>
<p><strong>MicroPython is blissfully unaware of Multitasking</strong></p>
<p>MicroPython runs mostly as a single task with a single stack. Easy peasy!</p>
<p>Mynewt runs with multiple tasks and multiple stacks. Tasks communicate by passing Events.</p>
<p>So it gets messy when we try to give MicroPython the illusion that it's running all alone by itself... MicroPython needs to share the CPU and RAM with Mynewt tasks now.</p>
</li>
<li>
<p><strong>wasp-os Complexity</strong></p>
<p>By inserting an embedded operating system (Mynewt) under MicroPython, it increases the complexity of the entire wasp-os firmware.</p>
<p>We'll have to manage this complexity very carefully: We shall make changes only to the MicroPython layer, not to the wasp-os layer.</p>
</li>
<li>
<p>And most ominous of all: <strong>I have failed before!</strong></p>
<p>My first hacking experience with MicroPython was on <a href="https://github.com/lupyuen/bluepill-micropython">STM32 Blue Pill</a>... It failed miserably.</p>
<p>But now I'm older, wiser and I have much better hardware (PineTime vs Blue Pill)... I might succeed!</p>
</li>
</ol>
<p>Here goes the experiment to assess whether it's really feasible to improve wasp-os by hosting it on top of Mynewt. </p>
<p>Our objective is simple: To boot up wasp-os on Mynewt and render a watch face on PineTime.</p>
<p>Read on for the details.</p>
<p><img src="https://lupyuen.github.io/images/micropython-watch.jpg" alt="Objective Accomplished! wasp-os rendering a watch face with Mynewt on PineTime. At right is the ST-Link debugger" /></p>
<p><em>Objective Accomplished! wasp-os rendering a watch face with Mynewt on PineTime. At right is the ST-Link debugger</em></p>
<h1 id="hardware-abstraction-layer-for-pinetime" class="section-header"><a href="#hardware-abstraction-layer-for-pinetime">3 Hardware Abstraction Layer for PineTime</a></h1>
<p>Embedded operating systems (like Mynewt) are designed to run on multuple hardware platforms (like PineTime). That's why they include a <a href="https://mynewt.apache.org/latest/os/modules/hal/hal.html"><strong>Hardware Abstraction Layer</strong></a> that wraps low-level <strong>hardware-specific code</strong> (like writing to SPI registers) into high-level <strong>hardware-independent functions</strong> (like sending a chunk of data to the SPI port).</p>
<p>The Hardware Abstraction Layer is used on PineTime like this...</p>
<p><img src="https://lupyuen.github.io/images/micropython-hal.png?1" alt="Hardware Abstraction Layer in PineTime" /></p>
<p>In MicroPython, the Hardware Abstraction Layers for various hardware platforms are located in the <strong>Ports</strong> folder, coded in C...</p>
<ul>
<li><strong>MicroPython Ports:</strong> <a href="https://github.com/micropython/micropython/tree/master/ports"><code>github.com/micropython/micropython/ports</code></a></li>
</ul>
<p>PineTime uses the <strong>nRF Port</strong>, which runs on nRF51 and nRF52 hardware...</p>
<ul>
<li><strong>MicroPython nRF Port:</strong> <a href="https://github.com/micropython/micropython/tree/master/ports/nrf"><code>ports/nrf</code></a></li>
</ul>
<p>For this experiment we cloned the nRF Port to create a new <strong>Mynewt Port</strong> that will run on Mynewt (instead of bare hardware)...</p>
<ul>
<li><strong>MicroPython Mynewt Port:</strong> <a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt"><code>ports/mynewt</code></a></li>
</ul>
<p>Let's look inside the Mynewt Port.</p>
<h1 id="mynewt-port-for-micropython" class="section-header"><a href="#mynewt-port-for-micropython">4 Mynewt Port for MicroPython</a></h1>
<p>Remember that a MicroPython Port works like a Hardware Abstraction Layer... It contains high-level functions for accessing the GPIO, SPI and I2C hardware interfaces.  Let's learn how the Mynewt Port of MicroPython implements these high-level functions in C.</p>
<h2 id="configuration" class="section-header"><a href="#configuration">4.1 Configuration</a></h2>
<p>Here are the configuration files for the Mynewt Port of MicroPython...</p>
<ul>
<li>
<p><a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/mpconfigport.h"><code>mpconfigport.h</code></a>: Configures MicroPython Runtime features, like REPL and code compilation</p>
</li>
<li>
<p><a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/boards/pinetime/mpconfigboard.h"><code>boards/pinetime/mpconfigboard.h</code></a>: Configures PineTime's Hardware features, like SPI</p>
</li>
<li>
<p><a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/boards/pinetime/pins.csv"><code>boards/pinetime/pins.csv</code></a>: Defines PineTime's Hardware Pins and their functions (GPIO, SPI, I2C)</p>
</li>
</ul>
<h2 id="peripheral-drivers-gpio-i2c-spi" class="section-header"><a href="#peripheral-drivers-gpio-i2c-spi">4.2 Peripheral Drivers: GPIO, I2C, SPI</a></h2>
<p>PineTime's nRF52 Microcontroller has onboard functions like GPIO, I2C, SPI, UART, Timers, ... We call them <strong>Peripherals</strong>.</p>
<ul>
<li>
<p><a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt/modules/machine"><code>modules/machine</code></a> folder contains the driver code in C for the nRF52 Peripherals</p>
</li>
<li>
<p>We have reprogrammed the GPIO, SPI and I2C Drivers to work with Mynewt's Hardware Abstraction Layer. More about this later.</p>
</li>
<li>
<p>Peripheral Drivers from MicroPython that we haven't ported to Mynewt: Analog-to-Digital Converter, Pulse Width Modulation, Real Time Clock, Temperature Sensor, Timer, UART</p>
</li>
</ul>
<h2 id="other-drivers" class="section-header"><a href="#other-drivers">4.3 Other Drivers</a></h2>
<p>There are other MicroPython drivers for PineTime's nRF52 Microcontroller that we haven't ported to Mynewt yet. The drivers may be found in these folders...</p>
<ul>
<li>
<p><a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt/modules"><code>modules</code></a>: Bluetooth LE, LED, Music, Random Number Generator, BluePy, OS, Time</p>
</li>
<li>
<p><a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt/drivers"><code>drivers</code></a>: Bluetooth, Flash ROM, Soft PWM, Ticker, Watchdog</p>
</li>
</ul>
<h2 id="start-micropython" class="section-header"><a href="#start-micropython">4.4 Start MicroPython</a></h2>
<ul>
<li>
<p><a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/main.c"><code>main.c</code></a> contains the <code>start_micropython()</code> function that starts the MicroPython Runtime (including the REPL command line)</p>
</li>
<li>
<p><code>start_micropython()</code> is called by Mynewt during startup</p>
</li>
<li>
<p>Heap Memory for MicroPython is also defined in <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/main.c"><code>main.c</code></a> as a Static Array. More about this later.</p>
</li>
</ul>
<h2 id="reset-handler-vector-table-and-linker-script" class="section-header"><a href="#reset-handler-vector-table-and-linker-script">4.5 Reset Handler, Vector Table and Linker Script</a></h2>
<p>Every PineTime Firmware requires a <strong>Reset Handler</strong> function to defined. It's the first function that's called when the firmware starts.</p>
<p>The firmware should also contain a <strong>Vector Table</strong>, which is a list of pointers to functions that will handle interrupts and exceptions on PineTime.</p>
<p>The <strong>Linker Script</strong> is used by the GCC Linker while building the firmware to determine the addresses in ROM and RAM for placing the firmware code and data.</p>
<p>The Reset Handler, Vector Table and Linker Script are mandatory for every MicroPython Port (including the nRF Port). But for the Mynewt Port, they are not used because we'll be using the Reset Handler, Vector Table and Linker Script from Mynewt instead.</p>
<ul>
<li>
<p><a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt/device"><code>device</code></a> folder contains the MicroPython Reset Handler and Vector Table</p>
<p>They are not used in the Mynewt Port, we're using the Reset Handler and Vector Table from Mynewt: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/hw/bsp/nrf52/src/arch/cortex_m4/gcc_startup_nrf52.s"><code>hw/bsp/nrf52/src/arch/cortex_m4/gcc_startup_nrf52.s</code></a></p>
</li>
<li>
<p><a href="https://github.com/AppKaki/micropython/tree/wasp-os/ports/mynewt/boards"><code>boards</code></a> folder contains the MicroPython Linker Script</p>
<p>This Linker Script is not used in the Mynewt Port, we're using the Linker Script from Mynewt: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/hw/bsp/nrf52/nrf52xxaa.ld"><code>hw/bsp/nrf52/nrf52xxaa.ld</code></a></p>
</li>
</ul>
<p>Let's study the code for the GPIO, SPI and I2C Drivers in the Mynewt Port for MicroPython... And understand how they call Mynewt's Hardware Abstraction Layer.</p>
<p><img src="https://lupyuen.github.io/images/micropython-hal1.png" alt="GPIO Driver" /></p>
<h1 id="gpio-driver" class="section-header"><a href="#gpio-driver">5 GPIO Driver</a></h1>
<p>The GPIO Driver is essential for our demo... Because PineTime's Backlight is controlled by GPIO and PineTime's screen will be totally dark without the Backlight!</p>
<p>Let's look at the current implementation of the GPIO Driver on MicroPython: <a href="https://github.com/micropython/micropython/blob/master/ports/nrf/mphalport.h"><code>ports/nrf/mphalport.h</code></a></p>
<pre><code class="language-c">#define mp_hal_pin_high(p) \
        nrf_gpio_pin_set(p-&gt;pin)

#define mp_hal_pin_low(p) \     
        nrf_gpio_pin_clear(p-&gt;pin)
</code></pre>
<p>To set a pin high or low, the GPIO Driver (from the nRF Port) calls the functions <code>nrf_gpio_pin_set()</code> and <code>nrf_gpio_pin_clear()</code>, which are provided by the <a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/group__nrf__gpio__hal.html">Nordic nRF5 SDK</a></p>
<p>Clearly this GPIO Driver (nRF Port) is directly manipulating the bare hardware of PineTime.</p>
<p>Compare that with the Mynewt Port: <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/mphalport.h"><code>ports/mynewt/mphalport.h</code></a></p>
<pre><code class="language-c">#define mp_hal_pin_high(p) \
        hal_gpio_write(p-&gt;pin, 1)

#define mp_hal_pin_low(p) \
        hal_gpio_write(p-&gt;pin, 0)
</code></pre>
<p>This GPIO Driver calls the functions <code>hal_gpio_write()</code> and <code>hal_gpio_write()</code> provided by <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html"><strong>Mynewt's Hardware Abstraction Layer</strong></a>.</p>
<p>Thus we are no longer manipulating PineTime hardware directly... We are doing it through an embedded operating system (Mynewt).</p>
<p>And we get to enjoy all the benefits of the embedded operating system! Multitasking, firmware updates, Bluetooth support, ...</p>
<p>Here's how we configure and read a GPIO pin by calling <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html">Mynewt's Hardware Abstraction Layer</a>... </p>
<pre><code class="language-c">#define mp_hal_pin_read(p) \
        hal_gpio_read(p-&gt;pin)

#define mp_hal_pin_open_drain(p) \
        hal_gpio_init_in(p-&gt;pin, HAL_GPIO_PULL_NONE)
</code></pre>
<p>With this simple reprogramming, we have done enough to switch on PineTime's Backlight for our experiment.</p>
<p>Some GPIO functions have yet to be implemented, like in <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/modules/machine/pin.c"><code>modules/machine/pin.c</code></a>...</p>
<pre><code class="language-c">STATIC mp_obj_t pin_irq(
    size_t n_args, 
    const mp_obj_t *pos_args, 
    mp_map_t *kw_args) { ...
</code></pre>
<p><code>pin_irq()</code> is called by MicroPython to configure the interrupt that will be triggered when an input GPIO pin switches its state from high to low (or low to high). This will be useful for handling the pressing of PineTime's watch button, since it's connected to a GPIO pin.</p>
<p>Eventually <code>pin_irq()</code> shall be reprogrammed to call the equivalent function in Mynewt: <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html#c.hal_gpio_irq_init"><code>hal_gpio_irq_init()</code></a></p>
<p>Moving on to SPI...</p>
<p><img src="https://lupyuen.github.io/images/micropython-hal2.png" alt="SPI Driver" /></p>
<h1 id="spi-driver" class="section-header"><a href="#spi-driver">6 SPI Driver</a></h1>
<p>Now that we have reprogrammed the GPIO Driver from Bare Metal PineTime to Mynewt, let's do the same for the SPI Driver. </p>
<p>PineTime's <a href="https://wiki.pine64.org/images/5/54/ST7789V_v1.6.pdf">Sitronix ST77889 Display Controller</a> is controlled via SPI, thus we shall port the SPI Driver to Mynewt for rendering graphics.</p>
<p>Porting the SPI Driver really is really easy... No initialisation needed!</p>
<p>Mynewt starts its SPI Driver automatically upon startup, according to the settings in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/syscfg.yml"><code>apps/my_sensor_app/syscfg.yml</code></a></p>
<pre><code class="language-yaml"># System Configuration Setting Values:
#   Below we override the driver and library settings. Settings defined in
#   targets/nrf52_my_sensor/syscfg.yml will override the settings below.

syscfg.vals:
    SPI_0_MASTER: 1  # Enable SPI port 0 for ST7789 display and SPI Flash
</code></pre>
<p>The pins for the SPI port are defined in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/hw/bsp/nrf52/syscfg.yml"><code>hw/bsp/nrf52/syscfg.yml</code></a></p>
<pre><code class="language-yaml">syscfg.vals:
    ###########################################################################
    # Default Pins for Peripherals
    # Defined in http://files.pine64.org/doc/PineTime/PineTime%20Port%20Assignment%20rev1.0.pdf

    # SPI port 0 connected to ST7789 display and XT25F32B flash
    SPI_0_MASTER_PIN_SCK:  2  # P0.02/AIN0: SPI-SCK, LCD_SCK    SPI clock for display and flash
    SPI_0_MASTER_PIN_MOSI: 3  # P0.03/AIN1: SPI-MOSI, LCD_SDI   SPI MOSI for display and flash
    SPI_0_MASTER_PIN_MISO: 4  # P0.04/AIN2: SPI-MISO            SPI MISO for flash only
</code></pre>
<p>What about the MicroPython driver code? Only one SPI Driver function needs to be reprogrammed in <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/modules/machine/spi.c"><code>modules/machine/spi.c</code></a></p>
<pre><code class="language-c">/// Called by MicroPython to transmit and receive a chunk of data over the SPI port
void spi_transfer(
    const machine_hard_spi_obj_t * self,  //  MicroPython instance of the SPI Driver (not used here)
    size_t len,         //  Number of bytes to send / receive
    const void * src,   //  Transmit Buffer
    void * dest         //  Receive Buffer
) {
    int rc = hal_spi_txrx(
        SPI_PORT,       //  Mynewt SPI Port (hardcoded to 0)
        (void *) src,   //  Transmit Buffer
        dest,           //  Receive Buffer
        len             //  Length
    );
    if (rc != 0) { mp_raise_ValueError(&quot;SPI TX failed&quot;); }
}
</code></pre>
<p>Whenever MicroPython calls <code>spi_transfer()</code> in our Mynewt Port to transmit and receive a chunk of data over SPI, we forward the call to <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_spi/hal_spi.html#c.hal_spi_txrx"><code>hal_spi_txrx()</code></a>. That's the equivalent SPI function in the Mynewt Hardware Abstraction Layer.</p>
<p><em>The SPI Driver in the Mynewt Port for MicroPython is now ready!</em></p>
<p>We'll see the SPI Driver in action when wasp-os's ST7789 Driver calls our SPI Driver to render the watch face: <a href="https://github.com/lupyuen/wasp-os/blob/master/wasp/drivers/st7789.py"><code>wasp/drivers/st7789.py</code></a></p>
<p>Finally, I2C...</p>
<p><img src="https://lupyuen.github.io/images/micropython-hal3.png" alt="I2C Driver" /></p>
<h1 id="i2c-driver" class="section-header"><a href="#i2c-driver">7 I2C Driver</a></h1>
<p>We won't be using the I2C Driver in the demo, because we won't be handling touch events from PineTime's Touch Controller.  But for completeness, here's how we ported MicroPython's I2C Driver to Mynewt...</p>
<p>Mynewt starts the I2C port automatically upon startup because of the settings in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/syscfg.yml"><code>apps/my_sensor_app/syscfg.yml</code></a></p>
<pre><code class="language-yaml"># System Configuration Setting Values:
#   Below we override the driver and library settings. Settings defined in
#   targets/nrf52_my_sensor/syscfg.yml will override the settings below.

syscfg.vals:
    I2C_1: 1  # Enable I2C port 1 for CST816S touch controller, BMA421 accelerometer, HRS3300 heart rate sensor
</code></pre>
<p>The I2C pins are configured in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/hw/bsp/nrf52/syscfg.yml"><code>hw/bsp/nrf52/syscfg.yml</code></a></p>
<pre><code class="language-yaml">syscfg.vals:
    ###########################################################################
    # Default Pins for Peripherals
    # Defined in http://files.pine64.org/doc/PineTime/PineTime%20Port%20Assignment%20rev1.0.pdf

    # I2C port 1 connected to CST816S touch controller, BMA421 accelerometer, HRS3300 heart rate sensor 
    I2C_1_PIN_SCL: 7  # P0.07: BMA421-SCL, HRS3300-SCL, TP-SCLOUT
    I2C_1_PIN_SDA: 6  # P0.06: BMA421-SDA, HRS3300-SDA, TP-SDAI/O
</code></pre>
<p>Note that the SPI and I2C ports are numbered globally in Mynewt... SPI goes to port 0 (<code>SPI_0</code>) and I2C goes to port 1 (<code>I2C_1</code>).  Thus we should never attempt to configure <code>SPI_1</code> or <code>I2C_0</code>.</p>
<p>Here's how we configure the I2C frequency for MicroPython: <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/modules/machine/i2c.c"><code>modules/machine/i2c.c</code></a></p>
<pre><code class="language-c">/// Called by MicroPython to initialise the I2C port
mp_obj_t machine_hard_i2c_make_new(
    const mp_obj_type_t *type,
    size_t n_args, 
    size_t n_kw, 
    const mp_obj_t *all_args
) {
    struct hal_i2c_settings settings = {
        .frequency = 400,     //  Set to the highest I2C frequency: 400 Kbps
    };
    int rc = hal_i2c_config(  //  Call Mynewt I2C HAL
        I2C_PORT,             //  Mynewt I2C Port (hardcoded to 1)
        &amp;settings
    );
    if (rc != 0) { mp_raise_ValueError(&quot;I2C init failed&quot;); }
    const machine_hard_i2c_obj_t *self = &amp;machine_hard_i2c_obj[I2C_PORT];
    return MP_OBJ_FROM_PTR(self);
}
</code></pre>
<p>The code above calls <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_i2c/hal_i2c.html#c.hal_i2c_config"><code>hal_i2c_config()</code></a> from Mynewt's I2C Hardware Abstraction Layer.</p>
<p>Here's how we transmit and receive I2C packets for MicroPython: <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/modules/machine/i2c.c"><code>modules/machine/i2c.c</code></a></p>
<pre><code class="language-c">/// Transmit or receive the buffer via I2C. Return the number of bytes transferred, or in case of error, a negative MP error code.
int machine_hard_i2c_transfer_single(
    mp_obj_base_t *self_in,  //  MicroPython instance of the I2C Driver (not used here)
    uint16_t addr,           //  I2C target address
    size_t len,              //  Number of bytes to transfer / receive
    uint8_t *buf,            //  Buffer to transfer and receive
    unsigned int flags       //  Whether this is a read or write operation
) {
    //  Set the transmit/receive parameters
    struct hal_i2c_master_data master_data = {
        .address = addr,
        .len = len,
        .buffer = buf,
    };
    if (flags &amp; MP_MACHINE_I2C_FLAG_READ) {   //  If reading from I2C...
        int rc_read = hal_i2c_master_read(    //  Call Mynewt I2C HAL to receive data
            I2C_PORT,                         //  Mynewt I2C Port (hardcoded to 1)
            &amp;master_data,                     //  Data will be received here
            I2C_TIMEOUT,                      //  Timeout in milliseconds (1,000)
            1  //  1 means this is the last I2C operation. So we can terminate after this.
        );    
        if (rc_read != 0) { return check_i2c_return_code(rc_read); }
    } else {                                  //  If writing to I2C...
        int rc_write = hal_i2c_master_write(  //  Call Mynewt I2C HAL to transmit data
            I2C_PORT,                         //  Mynewt I2C Port (hardcoded to 1)
            &amp;master_data,                     //  Data to be transmitted
            I2C_TIMEOUT,                      //  Timeout in milliseconds (1,000)
            1  //  1 means this is the last I2C operation. So we can terminate after this.
        );
        if (rc_write != 0) { return check_i2c_return_code(rc_write); }
    }
    return len;
}
</code></pre>
<p>The code above calls <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_i2c/hal_i2c.html#c.hal_i2c_master_read"><code>hal_i2c_master_read()</code></a> and <a href="https://mynewt.apache.org/latest/os/modules/hal/hal_i2c/hal_i2c.html#c.hal_i2c_master_write"><code>hal_i2c_master_write()</code></a> from Mynewt's I2C Hardware Abstraction Layer.</p>
<p><em>How is this I2C Driver used in wasp-os?</em></p>
<p>Check out the driver for the CST816S Touch Controller: <a href="https://github.com/lupyuen/wasp-os/blob/master/wasp/drivers/cst816s.py"><code>wasp/drivers/cst816s.py</code></a></p>
<h1 id="heap-memory-in-micropython" class="section-header"><a href="#heap-memory-in-micropython">8 Heap Memory in MicroPython</a></h1>
<p><em>How is RAM used by MicroPython?</em></p>
<p>When MicroPython runs on Bare Metal (without an operating system), it uses three chunks of RAM to store objects...</p>
<ol>
<li>
<p><strong>Static Memory</strong>: Contains C objects that are Global or Static</p>
</li>
<li>
<p><strong>Stack Memory</strong>: Contains C objects allocated on the stack inside function calls</p>
</li>
<li>
<p><strong>Heap Memory</strong>: Contains MicroPython objects allocated dynamically, similar to calling <code>malloc()</code> in C</p>
</li>
</ol>
<p><img src="https://lupyuen.github.io/images/micropython-heap2.png" alt="RAM Usage with MicroPython" /></p>
<p>Note that the Heap Memory and Stack Memory are not fixed.  They are allowed to grow and shrink, as long as the combined size fits within RAM.</p>
<p><em>What happens when Stack Memory gets too close to Heap Memory?</em></p>
<p>MicroPython performs Garbage Collection. It scans the Heap Memory and reclaims unused space for new objects.</p>
<p><em>What happens when we run MicroPython on a multitasking operating system like Mynewt?</em></p>
<p>With multitasking, all RAM needs to be carefully budgeted and partitioned like this...</p>
<p><img src="https://lupyuen.github.io/images/micropython-heap.png" alt="RAM Usage with Mynewt and MicroPython" /></p>
<ol>
<li>
<p><strong>Mbuf Memory</strong>: <a href="https://mynewt.apache.org/latest/os/core_os/mbuf/mbuf.html">Mbufs (Memory Buffers)</a> are used for Bluetooth LE networking and by the Semihosting Console in Mynewt. Mbufs are fixed-size blocks of 110 bytes that may be chained together to form larger objects.</p>
<p><em>Why are Mbufs fixed size?</em> </p>
<p>To prevent <a href="https://stackoverflow.com/questions/3770457/what-is-memory-fragmentation">fragmentation of the memory space</a>. Though coding with Mbufs is slightly more difficult.</p>
</li>
<li>
<p><strong>Idle Task</strong>: With multitasking, there is no longer a common stack. Each task now requires its own Stack Memory. Even the Idle Task, which runs when no other tasks are running.</p>
</li>
<li>
<p><strong>Main Task</strong>: This is the task that runs the MicroPython Runtime. The Stack Memory in the Main Task is used by MicroPython.</p>
</li>
<li>
<p><strong>Bluetooth Task</strong>: This is the background task that handles Bluetooth LE packets. It requires its own Stack Memory too.</p>
</li>
</ol>
<p>We no longer enjoy the grow-and-shink memory model that we have seen earlier... Every memory space must have a fixed size!</p>
<p>That's why we often discourage the use of Heap Memory on embedded operating systems... We can't really be sure when we'll run out of Heap Memory!</p>
<p>Let's find out how we allocated the Heap Memory in Mynewt.</p>
<h1 id="heap-memory-in-mynewt" class="section-header"><a href="#heap-memory-in-mynewt">9 Heap Memory in Mynewt</a></h1>
<p>For the Mynewt port of MicroPython, the Heap Memory is defined as a static array of 32 KB: <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/main.c"><code>ports/mynewt/main.c</code></a></p>
<pre><code class="language-c">/// Heap Memory for MicroPython
#define MICROPYTHON_HEAP_SIZE 32768
uint8_t micropython_heap[MICROPYTHON_HEAP_SIZE];

/// Called my Mynewt to start the MicroPython runtime
int start_micropython(void) {
    ...
    // Set the top of the stack
    void *stack_start = get_micropython_stack_start();
    void *stack_end   = get_micropython_stack_end();
    mp_stack_set_top(stack_end);

    // Stack limit not applicable to Mynewt, since stack and heap are in different regions
    mp_stack_set_limit((char*) stack_end - (char*) stack_start);

    // Initialise the Mynewt port
    machine_init();

    //  Allocate the MicroPython heap memory
    void *heap_start = &amp;micropython_heap[0];
    void *heap_end   = &amp;micropython_heap[MICROPYTHON_HEAP_SIZE];
    gc_init(heap_start, heap_end);
</code></pre>
<p>Note that the Stack Limit checking has been disabled, since we don't support grow-and-shrink Heap Memory with Mynewt.</p>
<p>32 KB is not a lot of Heap Memory... But it's sufficient for wasp-os to render a watch face on PineTime (which has 64 KB RAM).</p>
<p>The Stack Memory and Mbuf Memory sizes are defined in Mynewt: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/syscfg.yml"><code>apps/my_sensor_app/syscfg.yml</code></a></p>
<pre><code class="language-yaml">syscfg.vals:
    OS_MAIN_STACK_SIZE: 2048  #  Main stack (includes MicroPython) is 8 KB. Previously 4096 (16 KB)

    # For Bluetooth LE: Lots of smaller mbufs are required for newtmgr using typical BLE ATT MTU values.
    MSYS_1_BLOCK_COUNT:   22  #  Defaults to 12. Previously 64
    MSYS_1_BLOCK_SIZE:   110  #  Defaults to 292
</code></pre>
<p>We reserved 8 KB of Stack Memory for Mynewt's Main Task, which also executes the MicroPython Runtime.</p>
<p>For the Mbuf Memory we allocated 22 Mbufs of 110 bytes each (total 2,420 bytes).</p>
<p>This Mbuf Memory setting was recommended because we'll be using <a href="https://github.com/apache/mynewt-mcumgr">MCU Manager</a> (Simple Management Protocol) to upload firmware files during firmware update. See <a href="https://github.com/JuulLabs-OSS/mynewt-travis-ci/blob/master/newt_dump/proj/repos/apache-mynewt-nimble/apps/bleprph/syscfg.yml"><code>apache-mynewt-nimble/apps/bleprph/syscfg.yml</code></a></p>
<p><em>How much RAM and ROM are used by MicroPython on Mynewt?</em></p>
<p>According to the build output, the MicroPython Runtime takes up <strong>33 KB of RAM</strong>. That includes 32 KB of Heap Memory that we have allocated above.</p>
<p>The compiled MicroPython Runtime code occupies <strong>210 KB</strong> of Flash ROM.</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
  <span class="ident">FLASH</span>     <span class="ident">RAM</span> 
 <span class="number">214606</span>   <span class="number">33557</span> <span class="ident">libs_micropython</span>.<span class="ident">a</span></pre></div>
<p>The MicroPython Runtime is compiled as a custom library in Mynewt, hence the name <code>libs_micropython.a</code>. <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/build-app.sh#L164-L189">See the build script</a></p>
<p>The combined MicroPython + Mynewt firmware (including the NimBLE Bluetooth Stack) occupies <strong>340 KB of Flash ROM, 53 KB of RAM</strong>...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
   <span class="ident">text</span>    <span class="ident">data</span>     <span class="ident">bss</span>
 <span class="number">347992</span>     <span class="number">984</span>   <span class="number">54728</span></pre></div>
<p>Hence MicroPython takes up 62% of the firmware ROM, 61% of the firmware RAM.</p>
<p>Here are the ROM and RAM sizes of all code modules in the MicroPython + Mynewt firmware...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="op">+</span> <span class="ident">newt</span> <span class="ident">size</span> <span class="op">-</span><span class="ident">v</span> <span class="ident">nrf52_my_sensor</span>
<span class="ident">Size</span> <span class="ident">of</span> <span class="ident">Application</span> <span class="ident">Image</span>: <span class="ident">app</span>
<span class="ident">Mem</span> <span class="ident">FLASH</span>: <span class="number">0x8000</span><span class="op">-</span><span class="number">0x7bc00</span>
<span class="ident">Mem</span> <span class="ident">RAM</span>: <span class="number">0x20000000</span><span class="op">-</span><span class="number">0x20010000</span>
  <span class="ident">FLASH</span>     <span class="ident">RAM</span> 
    <span class="number">800</span>     <span class="number">324</span> <span class="kw-2">*</span><span class="ident">fill</span><span class="op">*</span>
   <span class="number">1018</span>      <span class="number">98</span> <span class="ident">apps_my_sensor_app</span>.<span class="ident">a</span>
   <span class="number">2268</span>     <span class="number">116</span> <span class="ident">boot_bootutil</span>.<span class="ident">a</span>
     <span class="number">18</span>       <span class="number">0</span> <span class="ident">boot_mynewt_flash_map_backend</span>.<span class="ident">a</span>
    <span class="number">438</span>      <span class="number">26</span> <span class="ident">boot_split</span>.<span class="ident">a</span>
   <span class="number">1180</span>       <span class="number">0</span> <span class="ident">crypto_mbedtls</span>.<span class="ident">a</span>
   <span class="number">2302</span>       <span class="number">0</span> <span class="ident">crypto_tinycrypt</span>.<span class="ident">a</span>
    <span class="number">401</span>       <span class="number">0</span> <span class="ident">encoding_base64</span>.<span class="ident">a</span>
   <span class="number">1622</span>       <span class="number">0</span> <span class="ident">encoding_cborattr</span>.<span class="ident">a</span>
   <span class="number">3002</span>       <span class="number">0</span> <span class="ident">encoding_tinycbor</span>.<span class="ident">a</span>
    <span class="number">452</span>     <span class="number">444</span> <span class="ident">hw_bsp_nrf52</span>.<span class="ident">a</span>
     <span class="number">52</span>       <span class="number">0</span> <span class="ident">hw_cmsis</span><span class="op">-</span><span class="ident">core</span>.<span class="ident">a</span>
   <span class="number">1560</span>      <span class="number">92</span> <span class="ident">hw_drivers_flash_spiflash</span>.<span class="ident">a</span>
    <span class="number">706</span>       <span class="number">1</span> <span class="ident">hw_hal</span>.<span class="ident">a</span>
   <span class="number">6646</span>      <span class="number">89</span> <span class="ident">hw_mcu_nordic_nrf52xxx</span>.<span class="ident">a</span>
      <span class="number">2</span>       <span class="number">0</span> <span class="ident">hw_sensor_creator</span>.<span class="ident">a</span>
   <span class="number">1264</span>     <span class="number">260</span> <span class="ident">hw_sensor</span>.<span class="ident">a</span>
   <span class="number">8790</span>   <span class="number">11296</span> <span class="ident">kernel_os</span>.<span class="ident">a</span>
   <span class="number">3152</span>      <span class="number">50</span> <span class="ident">libc_baselibc</span>.<span class="ident">a</span>
 <span class="number">214606</span>   <span class="number">33557</span> <span class="ident">libs_micropython</span>.<span class="ident">a</span>
     <span class="number">16</span>       <span class="number">0</span> <span class="ident">libs_mynewt_rust</span>.<span class="ident">a</span>
   <span class="number">1410</span>       <span class="number">0</span> <span class="ident">libs_rust_app</span>.<span class="ident">a</span>
   <span class="number">1014</span>       <span class="number">0</span> <span class="ident">libs_rust_libcore</span>.<span class="ident">a</span>
    <span class="number">738</span>      <span class="number">42</span> <span class="ident">libs_semihosting_console</span>.<span class="ident">a</span>
     <span class="number">40</span>       <span class="number">9</span> <span class="ident">libs_sensor_coap</span>.<span class="ident">a</span>
    <span class="number">583</span>      <span class="number">99</span> <span class="ident">libs_sensor_network</span>.<span class="ident">a</span>
    <span class="number">677</span>     <span class="number">212</span> <span class="ident">libs_temp_stub</span>.<span class="ident">a</span>
   <span class="number">3428</span>      <span class="number">72</span> <span class="ident">mgmt_imgmgr</span>.<span class="ident">a</span>
    <span class="number">231</span>      <span class="number">20</span> <span class="ident">mgmt_mgmt</span>.<span class="ident">a</span>
    <span class="number">884</span>     <span class="number">100</span> <span class="ident">mgmt_newtmgr</span>.<span class="ident">a</span>
   <span class="number">1410</span>      <span class="number">44</span> <span class="ident">mgmt_newtmgr_nmgr_os</span>.<span class="ident">a</span>
    <span class="number">454</span>     <span class="number">108</span> <span class="ident">mgmt_newtmgr_transport_ble</span>.<span class="ident">a</span>
    <span class="number">405</span>     <span class="number">388</span> <span class="ident">net_oic</span>.<span class="ident">a</span>
  <span class="number">35496</span>    <span class="number">2107</span> <span class="ident">nimble_controller</span>.<span class="ident">a</span>
   <span class="number">4086</span>    <span class="number">1203</span> <span class="ident">nimble_drivers_nrf52</span>.<span class="ident">a</span>
  <span class="number">41721</span>    <span class="number">2797</span> <span class="ident">nimble_host</span>.<span class="ident">a</span>
    <span class="number">822</span>     <span class="number">218</span> <span class="ident">nimble_host_services_ans</span>.<span class="ident">a</span>
    <span class="number">241</span>     <span class="number">112</span> <span class="ident">nimble_host_services_dis</span>.<span class="ident">a</span>
    <span class="number">396</span>     <span class="number">118</span> <span class="ident">nimble_host_services_gap</span>.<span class="ident">a</span>
    <span class="number">204</span>      <span class="number">62</span> <span class="ident">nimble_host_services_gatt</span>.<span class="ident">a</span>
   <span class="number">1814</span>     <span class="number">648</span> <span class="ident">nimble_host_store_config</span>.<span class="ident">a</span>
    <span class="number">114</span>       <span class="number">0</span> <span class="ident">nimble_host_util</span>.<span class="ident">a</span>
    <span class="number">692</span>    <span class="number">1096</span> <span class="ident">nimble_transport_ram</span>.<span class="ident">a</span>
   <span class="number">1578</span>      <span class="number">54</span> <span class="ident">sys_config</span>.<span class="ident">a</span>
    <span class="number">634</span>     <span class="number">128</span> <span class="ident">sys_flash_map</span>.<span class="ident">a</span>
      <span class="number">2</span>       <span class="number">0</span> <span class="ident">sys_log_modlog</span>.<span class="ident">a</span>
    <span class="number">686</span>      <span class="number">29</span> <span class="ident">sys_mfg</span>.<span class="ident">a</span>
    <span class="number">839</span>      <span class="number">51</span> <span class="ident">sys_reboot</span>.<span class="ident">a</span>
    <span class="number">226</span>      <span class="number">37</span> <span class="ident">sys_sysdown</span>.<span class="ident">a</span>
     <span class="number">30</span>       <span class="number">5</span> <span class="ident">sys_sysinit</span>.<span class="ident">a</span>
   <span class="number">1746</span>       <span class="number">0</span> <span class="ident">time_datetime</span>.<span class="ident">a</span>
    <span class="number">120</span>       <span class="number">0</span> <span class="ident">util_mem</span>.<span class="ident">a</span>
    <span class="number">208</span>       <span class="number">0</span> <span class="ident">nrf52_my_sensor</span><span class="op">-</span><span class="ident">sysinit</span><span class="op">-</span><span class="ident">app</span>.<span class="ident">a</span>
   <span class="number">2016</span>       <span class="number">0</span> <span class="ident">libgcc</span>.<span class="ident">a</span>
<span class="ident">Loading</span> <span class="ident">compiler</span> <span class="op">/</span><span class="ident">Users</span><span class="op">/</span><span class="ident">Luppy</span><span class="op">/</span><span class="ident">PineTime</span><span class="op">/</span><span class="ident">pinetime</span><span class="op">-</span><span class="ident">rust</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">repos</span><span class="op">/</span><span class="ident">apache</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">-</span><span class="ident">core</span><span class="op">/</span><span class="ident">compiler</span><span class="op">/</span><span class="ident">arm</span><span class="op">-</span><span class="ident">none</span><span class="op">-</span><span class="ident">eabi</span><span class="op">-</span><span class="ident">m4</span>, <span class="ident">buildProfile</span> <span class="ident">debug</span>

<span class="ident">objsize</span>
   <span class="ident">text</span>    <span class="ident">data</span>     <span class="ident">bss</span>     <span class="ident">dec</span>     <span class="ident">hex</span> <span class="ident">filename</span>
 <span class="number">347992</span>     <span class="number">984</span>   <span class="number">54728</span>  <span class="number">403704</span>   <span class="number">628f8</span> <span class="op">/</span><span class="ident">Users</span><span class="op">/</span><span class="ident">Luppy</span><span class="op">/</span><span class="ident">PineTime</span><span class="op">/</span><span class="ident">pinetime</span><span class="op">-</span><span class="ident">rust</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_my_sensor</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">apps</span><span class="op">/</span><span class="ident">my_sensor_app</span><span class="op">/</span><span class="ident">my_sensor_app</span>.<span class="ident">elf</span></pre></div>
<h1 id="nimble-bluetooth-stack" class="section-header"><a href="#nimble-bluetooth-stack">10 NimBLE Bluetooth Stack</a></h1>
<p>Mynewt includes the open-source <a href="https://github.com/apache/mynewt-nimble">NimBLE Bluetooth LE networking stack</a>, so we won't be using the <a href="https://infocenter.nordicsemi.com/topic/ug_gsg_ses/UG/gsg/softdevices.html">Nordic SoftDevice</a> Bluetooth stack from the nRF Port of MicroPython.</p>
<p>Let's flip NimBLE on and watch what happens. We'll add these NimBLE libraries to our firmware: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/pkg.yml"><code>apps/my_sensor_app/pkg.yml</code></a></p>
<pre><code class="language-yaml"># Bluetooth LE
pkg.deps.BLUETOOTH_LE:
    - &quot;@apache-mynewt-core/boot/split&quot;
    - &quot;@mcuboot/boot/bootutil&quot;
    - &quot;@apache-mynewt-core/mgmt/imgmgr&quot;
    - &quot;@apache-mynewt-core/mgmt/newtmgr&quot;
    - &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;
    - &quot;@apache-mynewt-nimble/nimble/host&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/services/ans&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/services/dis&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/services/gap&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/services/gatt&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/store/config&quot;
    - &quot;@apache-mynewt-nimble/nimble/host/util&quot;
    - &quot;@apache-mynewt-nimble/nimble/transport&quot;
</code></pre>
<p>Here are the libraries that we have added to our Mynewt + MicroPython firmware to support <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfu">Firmware Updates over Bluetooth LE</a>...</p>
<ul>
<li>
<p><code>mcuboot</code> is the open-source <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot">MCUBoot Bootloader</a> that we're using on PineTime. We include the <code>mcuboot</code> library so that PineTime Owners may query via Bluetooth LE the version number of the firmware that's installed.</p>
</li>
<li>
<p><code>imgmgr</code> writes the received firmware image to SPI Flash during Firmware Update</p>
</li>
<li>
<p><code>newtmgr</code> implements the <a href="https://github.com/apache/mynewt-mcumgr">MCU Manager</a>
Simple Management Protocol for uploading firmware images over Bluetooth LE</p>
</li>
<li>
<p><code>nimble</code> implements the Bluetooth LE Host and Transport functions (including GATT Services for Simple Management Protocol) by talking to the Bluetooth hardware on PineTime's nRF52 Microcontroller</p>
</li>
</ul>
<p><em>How do we start the Bluetooth LE services on PineTime?</em></p>
<p>In Mynewt's startup function <code>main()</code>, we call <code>start_ble()</code> to start the Bluetooth LE services: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/rust/app/src/lib.rs"><code>rust/app/src/lib.rs</code></a></p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="doccomment">/// Rust Main Function main() will be called at Mynewt startup. </span>
<span class="doccomment">/// It replaces the C version of the main() function.</span>
<span class="attribute">#[<span class="ident">no_mangle</span>]</span>                 <span class="comment">//  Don&#39;t mangle the name &quot;main&quot;</span>
<span class="kw">extern</span> <span class="string">&quot;C&quot;</span> <span class="kw">fn</span> <span class="ident">main</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="op">!</span> {  <span class="comment">//  Declare extern &quot;C&quot; because it will be called by Mynewt</span>
    <span class="comment">//  Initialise the Mynewt drivers. Any startup functions defined in pkg.yml </span>
    <span class="comment">//  of our custom drivers and libraries will be called by sysinit().  </span>
    <span class="comment">//  Here are the startup functions consolidated by Mynewt:</span>
    <span class="comment">//  bin/targets/nrf52_my_sensor/generated/src/nrf52_my_sensor-sysinit-app.c</span>
    <span class="ident">mynewt</span>::<span class="ident">sysinit</span>();

    <span class="comment">//  Start Bluetooth LE, including over-the-air firmware upgrade</span>
    <span class="kw">extern</span> { <span class="kw">fn</span> <span class="ident">start_ble</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="ident">i32</span>; }
    <span class="kw">let</span> <span class="ident">rc</span> <span class="op">=</span> <span class="kw">unsafe</span> { <span class="ident">start_ble</span>() };
    <span class="macro">assert</span><span class="macro">!</span>(<span class="ident">rc</span> <span class="op">=</span><span class="op">=</span> <span class="number">0</span>, <span class="string">&quot;BLE fail&quot;</span>);

    <span class="comment">//  Start MicroPython</span>
    <span class="kw">extern</span> { <span class="kw">fn</span> <span class="ident">start_micropython</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="ident">i32</span>; }
    <span class="kw">let</span> <span class="ident">rc</span> <span class="op">=</span> <span class="kw">unsafe</span> { <span class="ident">start_micropython</span>() };
    <span class="macro">assert</span><span class="macro">!</span>(<span class="ident">rc</span> <span class="op">=</span><span class="op">=</span> <span class="number">0</span>, <span class="string">&quot;MP fail&quot;</span>);
    ...</pre></div>
<p><code>start_ble()</code> is defined in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/src/ble_main.c"><code>my_sensor_app/src/ble_main.c</code></a>, which calls supporting Bluetooth LE functions in  <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/src/ble_gatt_svr.c"><code>ble_gatt_svr.c</code></a>, <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/src/ble_misc.c"><code>ble_misc.c</code></a>, <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/src/ble_phy.c"><code>ble_phy.c</code></a> and <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/apps/my_sensor_app/src/ble_prph.h"><code>ble_prph.h</code></a></p>
<p>Then <code>main()</code> calls <code>start_micropython()</code> to start the MicroPython Runtime, including wasp-os. We have seen <code>start_micropython()</code> in <a href="https://github.com/AppKaki/micropython/blob/wasp-os/ports/mynewt/main.c"><code>ports/mynewt/main.c</code></a></p>
<p>At the end of <code>main()</code> we see this: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/rust/app/src/lib.rs"><code>rust/app/src/lib.rs</code></a></p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="kw">extern</span> <span class="string">&quot;C&quot;</span> <span class="kw">fn</span> <span class="ident">main</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="op">!</span> {
    ...
    <span class="comment">//  Mynewt Event Loop</span>
    <span class="kw">loop</span> {                            <span class="comment">//  Loop forever...</span>
        <span class="ident">os</span>::<span class="ident">eventq_run</span>(               <span class="comment">//  Processing events...</span>
            <span class="ident">os</span>::<span class="ident">eventq_dflt_get</span>()     <span class="comment">//  From default event queue.</span>
                .<span class="ident">expect</span>(<span class="string">&quot;GET fail&quot;</span>)
        ).<span class="ident">expect</span>(<span class="string">&quot;RUN fail&quot;</span>);
    }</pre></div>
<p>This is the <strong>Event Loop</strong> for Mynewt. It's critical because any Bluetooth LE packets received will be treated as Mynewt Events and will be handled in this loop.</p>
<p><em>So does Bluetooth LE work?</em></p>
<p>Sadly no! There's a conflict with the Task Scheduling in Mynewt and MicroPython. More about this in the next section.</p>
<p><em>Wait a minute... The <code>main()</code> function is in Rust not C!</em></p>
<p>Yep! We're using a <a href="https://medium.com/@ly.lee/debug-rust-mynewt-firmware-for-pinetime-on-raspberry-pi-4b9ac2d093a9?source=friends_link&amp;sk=edb508c31e43d3ec40ecd8554f3405f6">variant of Mynewt that supports Rust</a>!</p>
<p>So technically we're calling: <strong>C (Mynewt) → Rust → MicroPython!</strong></p>
<p><em>But won't Rust bloat our Mynewt + MicroPython firmware unnecessarily?</em></p>
<p>Not at all! The Rust Application and Rust Core Library occupy only 2.4 KB of ROM, 0 KB of RAM! Amazing!</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
  <span class="ident">FLASH</span>     <span class="ident">RAM</span> 
   <span class="number">1410</span>       <span class="number">0</span> <span class="ident">libs_rust_app</span>.<span class="ident">a</span>
   <span class="number">1014</span>       <span class="number">0</span> <span class="ident">libs_rust_libcore</span>.<span class="ident">a</span></pre></div>
<h1 id="task-scheduling-micropython-vs-mynewt" class="section-header"><a href="#task-scheduling-micropython-vs-mynewt">11 Task Scheduling: MicroPython vs Mynewt</a></h1>
<p>We have just enabled the NimBLE Bluetooth Stack on our Mynewt + MicroPython firmware... But we can't scan our PineTime device on the <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfutest">Nordic nRF Connect mobile app</a>. Why?</p>
<p>Let's look again at the <code>main()</code> function: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/rust/app/src/lib.rs"><code>rust/app/src/lib.rs</code></a></p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="doccomment">///  Rust Main Function main() will be called at Mynewt startup. It replaces the C version of the main() function.</span>
<span class="attribute">#[<span class="ident">no_mangle</span>]</span>                 <span class="comment">//  Don&#39;t mangle the name &quot;main&quot;</span>
<span class="kw">extern</span> <span class="string">&quot;C&quot;</span> <span class="kw">fn</span> <span class="ident">main</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="op">!</span> {  <span class="comment">//  Declare extern &quot;C&quot; because it will be called by Mynewt</span>
    <span class="comment">//  Initialise the Mynewt packages and internal temperature sensor driver. Any startup</span>
    <span class="comment">//  functions defined in pkg.yml of our custom drivers and libraries will be called by </span>
    <span class="comment">//  sysinit().  Here are the startup functions consolidated by Mynewt:</span>
    <span class="comment">//  bin/targets/nrf52_my_sensor/generated/src/nrf52_my_sensor-sysinit-app.c</span>
    <span class="ident">mynewt</span>::<span class="ident">sysinit</span>();

    <span class="comment">//  Start Bluetooth LE, including over-the-air firmware upgrade</span>
    <span class="kw">extern</span> { <span class="kw">fn</span> <span class="ident">start_ble</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="ident">i32</span>; }
    <span class="kw">let</span> <span class="ident">rc</span> <span class="op">=</span> <span class="kw">unsafe</span> { <span class="ident">start_ble</span>() };
    <span class="macro">assert</span><span class="macro">!</span>(<span class="ident">rc</span> <span class="op">=</span><span class="op">=</span> <span class="number">0</span>, <span class="string">&quot;BLE fail&quot;</span>);

    <span class="comment">//  Start MicroPython</span>
    <span class="kw">extern</span> { <span class="kw">fn</span> <span class="ident">start_micropython</span>() <span class="op">-</span><span class="op">&gt;</span> <span class="ident">i32</span>; }
    <span class="kw">let</span> <span class="ident">rc</span> <span class="op">=</span> <span class="kw">unsafe</span> { <span class="ident">start_micropython</span>() };
    <span class="macro">assert</span><span class="macro">!</span>(<span class="ident">rc</span> <span class="op">=</span><span class="op">=</span> <span class="number">0</span>, <span class="string">&quot;MP fail&quot;</span>);

    <span class="comment">//  OOPS: start_micropython() will never return,</span>
    <span class="comment">//  because it&#39;s stuck in a MicroPython Event Loop. So the</span>
    <span class="comment">//  Mynewt Event Loop below will never run...</span>

    <span class="comment">//  Mynewt Event Loop</span>
    <span class="kw">loop</span> {                            <span class="comment">//  Loop forever...</span>
        <span class="ident">os</span>::<span class="ident">eventq_run</span>(               <span class="comment">//  Processing events...</span>
            <span class="ident">os</span>::<span class="ident">eventq_dflt_get</span>()     <span class="comment">//  From default event queue.</span>
                .<span class="ident">expect</span>(<span class="string">&quot;GET fail&quot;</span>)
        ).<span class="ident">expect</span>(<span class="string">&quot;RUN fail&quot;</span>);
    }
    <span class="comment">//  Never comes here</span>
}</pre></div>
<p>We see the watch face rendered by MicroPython and wasp-os, so <code>start_micropython()</code> must be working.</p>
<p>But there's a problem here... <code>start_micropython()</code> will be stuck in its own MicroPython Event Loop taking care of MicroPython tasks, so it never returns!</p>
<p>As a result, the Mynewt Event Loop will never be executed. And we know that the Mynewt Event Loop is critical for handling Bluetooth packets. Thus Bluetooth fails!</p>
<p>We have a conflict here between MicroPython and Mynewt and the way they handle tasks and events. We don't have a solution right now, but we'll probably need to modify the wasp-os / MicroPython Event Loop to handle Mynewt Events as well.</p>
<p>But for now, we have accomplished our objective of rendering a watch face on PineTime with wasp-os, MicroPython and Mynewt. Yay!</p>
<p>In the next section we'll learn to build the Mynewt + MicroPython firmware and flash it to PineTime.</p>
<p><img src="https://lupyuen.github.io/images/micropython-title.jpg" alt="MicroPython and wasp-os hosted on Mynewt on PineTime Smart Watch. VSCode Debugger is shown on the monitor" /></p>
<p><em>MicroPython and wasp-os hosted on Mynewt on PineTime Smart Watch. VSCode Debugger is shown on the monitor</em></p>
<h1 id="build-and-flash-mynewt--micropython-firmware" class="section-header"><a href="#build-and-flash-mynewt--micropython-firmware">12 Build and Flash Mynewt + MicroPython Firmware</a></h1>
<p>Follow these steps to build the Mynewt + MicroPython Firmware on Linux (including Raspberry Pi) and macOS...</p>
<h2 id="install-build-tools" class="section-header"><a href="#install-build-tools">12.1 Install Build Tools</a></h2>
<ol>
<li>
<p>Install GCC and Python build tools for Linux (or the macOS equivalent)...</p>
<pre><code class="language-bash">sudo apt install gcc gcc-arm-none-eabi python3 make
</code></pre>
</li>
<li>
<p>Install <code>rustup</code> with support for nightly target <code>thumbv7em-none-eabihf</code>. </p>
<p>Follow the instructions at https://rustup.rs/</p>
<p>Press Enter to select <code>1) Proceed with installation (default)</code></p>
<p>Then execute...</p>
<pre><code class="language-bash"># Latest nightly-2020-04-20 fails with asm error, so we use nightly-2020-02-16
source $HOME/.cargo/env
rustup default nightly-2020-02-16
rustup update
rustup target add thumbv7em-none-eabihf
</code></pre>
</li>
<li>
<p>Install the <code>newt</code> build tool for Mynewt.  Refer to these scripts...</p>
<ul>
<li>
<p><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/install-version.sh"><code>scripts/install-version.sh</code></a>: To set the version numbers</p>
</li>
<li>
<p><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/install-pi.sh"><code>scripts/install-pi.sh</code></a>: To build and install <code>newt</code>, look under the section <code>&quot;Build newt&quot;</code></p>
</li>
</ul>
</li>
</ol>
<h2 id="dowload-source-files" class="section-header"><a href="#dowload-source-files">12.2 Dowload Source Files</a></h2>
<p>We'll download the source files into these folders...</p>
<p><img src="https://lupyuen.github.io/images/micropython-folders.jpg" alt="Build folders for Mynewt + MicroPython Firmware" /></p>
<ol>
<li>
<p>Download the source files to <code>~/pinetime</code>...</p>
<pre><code class="language-bash">mkdir ~/pinetime
cd ~/pinetime
git clone --recursive --branch master https://github.com/lupyuen/wasp-os
git clone --recursive --branch micropython https://github.com/lupyuen/pinetime-rust-mynewt
</code></pre>
</li>
<li>
<p>Update the MCUBoot version number. Edit <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/project.yml"><code>~/pinetime/pinetime-rust-mynewt/project.yml</code></a></p>
<p>Change...</p>
<pre><code class="language-yaml">repository.mcuboot:
    type: github
    vers: 1.5.0
</code></pre>
<p>to...</p>
<pre><code class="language-yaml">repository.mcuboot:
    type: github
    vers: 1.3.1
</code></pre>
</li>
<li>
<p>Download the Mynewt source code...</p>
<pre><code class="language-bash">cd ~/pinetime/pinetime-rust-mynewt
newt install
</code></pre>
<p>We should see...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">Downloading</span> <span class="ident">repository</span> <span class="ident">mynewt</span><span class="op">-</span><span class="ident">core</span> (<span class="ident">commit</span>: <span class="ident">master</span>) <span class="ident">from</span> <span class="ident">https</span>:<span class="comment">//github.com/apache/mynewt-core.git</span>
<span class="ident">Downloading</span> <span class="ident">repository</span> <span class="ident">mynewt</span><span class="op">-</span><span class="ident">mcumgr</span> (<span class="ident">commit</span>: <span class="ident">master</span>) <span class="ident">from</span> <span class="ident">https</span>:<span class="comment">//github.com/apache/mynewt-mcumgr.git</span>
<span class="ident">Downloading</span> <span class="ident">repository</span> <span class="ident">mynewt</span><span class="op">-</span><span class="ident">nimble</span> (<span class="ident">commit</span>: <span class="ident">master</span>) <span class="ident">from</span> <span class="ident">https</span>:<span class="comment">//github.com/apache/mynewt-nimble.git</span>
<span class="ident">Downloading</span> <span class="ident">repository</span> <span class="ident">mcuboot</span> (<span class="ident">commit</span>: <span class="ident">master</span>) <span class="ident">from</span> <span class="ident">https</span>:<span class="comment">//github.com/JuulLabs-OSS/mcuboot.git</span>
<span class="ident">Making</span> <span class="ident">the</span> <span class="ident">following</span> <span class="ident">changes</span> <span class="ident">to</span> <span class="ident">the</span> <span class="ident">project</span>:
    <span class="ident">install</span> <span class="ident">apache</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">-</span><span class="ident">core</span> (<span class="number">1.7</span>.<span class="number">0</span>)
    <span class="ident">install</span> <span class="ident">apache</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">-</span><span class="ident">nimble</span> (<span class="number">1.2</span>.<span class="number">0</span>)
    <span class="ident">install</span> <span class="ident">mcuboot</span> (<span class="number">1.3</span>.<span class="number">1</span>)
<span class="ident">apache</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">-</span><span class="ident">core</span> <span class="ident">successfully</span> <span class="ident">installed</span> <span class="ident">version</span> <span class="number">1.7</span>.<span class="number">0</span>
<span class="ident">apache</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">-</span><span class="ident">nimble</span> <span class="ident">successfully</span> <span class="ident">installed</span> <span class="ident">version</span> <span class="number">1.2</span>.<span class="number">0</span>
<span class="ident">Error</span>: <span class="ident">Error</span> <span class="ident">updating</span> <span class="string">&quot;mcuboot&quot;</span>: <span class="ident">error</span>: <span class="ident">The</span> <span class="ident">following</span> <span class="ident">untracked</span> <span class="ident">working</span> <span class="ident">tree</span> <span class="ident">files</span> <span class="ident">would</span> <span class="ident">be</span> <span class="ident">overwritten</span> <span class="ident">by</span> <span class="ident">checkout</span>:
        <span class="ident">ext</span><span class="op">/</span><span class="ident">mbedtls</span><span class="op">/</span><span class="ident">include</span><span class="op">/</span><span class="ident">mbedtls</span><span class="op">/</span><span class="ident">check_config</span>.<span class="ident">h</span>
        <span class="ident">ext</span><span class="op">/</span><span class="ident">mbedtls</span><span class="op">/</span><span class="ident">include</span><span class="op">/</span><span class="ident">mbedtls</span><span class="op">/</span><span class="ident">config</span>.<span class="ident">h</span>
<span class="ident">Please</span> <span class="kw">move</span> <span class="ident">or</span> <span class="ident">remove</span> <span class="ident">them</span> <span class="ident">before</span> <span class="ident">you</span> <span class="ident">switch</span> <span class="ident">branches</span>.
<span class="ident">Aborting</span></pre></div>
<p>Ignore the <code>mcuboot</code> error above and proceed to the next step.</p>
</li>
</ol>
<h2 id="build-mynewt-firmware" class="section-header"><a href="#build-mynewt-firmware">12.3 Build Mynewt Firmware</a></h2>
<p>Build the Mynewt firmware (and generate the <code>syscfg.h</code> config file)...</p>
<pre><code class="language-bash">cd ~/pinetime/pinetime-rust-mynewt
scripts/build-app.sh
</code></pre>
<p>We should see...</p>

<pre><code>Linking my_sensor_app.elf
Error: ld: libc_baselibc.a(start.o): in function `_start&#39;:
start.c:39: undefined reference to `main&#39;
collect2: error: ld returned 1 exit status</code></pre>
<p>Ignore the <code>Undefined reference to main</code> error above and proceed to the next step.</p>
<h2 id="build-wasp-os-and-micropython" class="section-header"><a href="#build-wasp-os-and-micropython">12.4 Build wasp-os and MicroPython</a></h2>
<pre><code class="language-bash">cd ~/pinetime/wasp-os
export BUILD_VERBOSE=1
make -j 1 BOARD=pinetime micropython
</code></pre>
<p>We should see...</p>

<pre><code>arm-none-eabi-size build-pinetime/micropython.a
   text    data     bss     dec     hex filename
      0       0       0       0       0 mpstate.o (ex build-pinetime/micropython.a)
     32       0       0      32      20 nlr.o (ex build-pinetime/micropython.a)
      0       0       0       0       0 nlrx86.o (ex build-pinetime/micropython.a)
...
   1041       0       0    1041     411 pins_gen.o (ex build-pinetime/micropython.a)
make[1]: Leaving directory &#39;pinetime/wasp-os/micropython/ports/mynewt&#39;   </code></pre><h2 id="build-mynewt--micropython-firmware" class="section-header"><a href="#build-mynewt--micropython-firmware">12.5 Build Mynewt + MicroPython Firmware</a></h2>
<ol>
<li>
<p>Build the Mynewt firmware again...</p>
<pre><code class="language-bash">cd ~/pinetime/pinetime-rust-mynewt
scripts/build-app.sh
</code></pre>
<p>We should see...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">objsize</span>
<span class="ident">text</span>    <span class="ident">data</span>     <span class="ident">bss</span>     <span class="ident">dec</span>     <span class="ident">hex</span> <span class="ident">filename</span>
<span class="number">346216</span>     <span class="number">984</span>   <span class="number">54720</span>  <span class="number">401920</span>   <span class="number">62200</span> <span class="ident">pinetime</span><span class="op">/</span><span class="ident">pinetime</span><span class="op">-</span><span class="ident">rust</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_my_sensor</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">apps</span><span class="op">/</span><span class="ident">my_sensor_app</span><span class="op">/</span><span class="ident">my_sensor_app</span>.<span class="ident">elf</span>
<span class="op">+</span> <span class="ident">set</span> <span class="op">+</span><span class="ident">x</span>
<span class="op">+</span> <span class="ident">newt</span> <span class="ident">create</span><span class="op">-</span><span class="ident">image</span> <span class="ident">nrf52_my_sensor</span> <span class="number">1.0</span>.<span class="number">0</span>
<span class="ident">App</span> <span class="ident">image</span> <span class="ident">successfully</span> <span class="ident">generated</span>: <span class="ident">pinetime</span><span class="op">/</span><span class="ident">pinetime</span><span class="op">-</span><span class="ident">rust</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_my_sensor</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">apps</span><span class="op">/</span><span class="ident">my_sensor_app</span><span class="op">/</span><span class="ident">my_sensor_app</span>.<span class="ident">img</span>    </pre></div>
<p>If you see the error <code>Undefined main</code>, run <code>scripts/build-app.sh</code> again. It should fix the error.</p>
</li>
<li>
<p>Create the Firmware Image...</p>
<pre><code class="language-bash">scripts/nrf52/image-app.sh
</code></pre>
<p>We should see...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">App</span> <span class="ident">image</span> <span class="ident">successfully</span> <span class="ident">generated</span>: <span class="ident">pinetime</span><span class="op">/</span><span class="ident">pinetime</span><span class="op">-</span><span class="ident">rust</span><span class="op">-</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_my_sensor</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">apps</span><span class="op">/</span><span class="ident">my_sensor_app</span><span class="op">/</span><span class="ident">my_sensor_app</span>.<span class="ident">img</span>    </pre></div>
</li>
</ol>
<h2 id="select-the-openocd-interface-st-link-or-raspberry-pi-spi" class="section-header"><a href="#select-the-openocd-interface-st-link-or-raspberry-pi-spi">12.6 Select the OpenOCD Interface: ST-Link or Raspberry Pi SPI</a></h2>
<p>Edit <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/config.sh"><code>~/pinetime/pinetime-rust-mynewt/scripts/config.sh</code></a></p>
<p>If we're using ST-Link v2 for flashing PineTime, set <code>swd_device</code> as follows...</p>
<pre><code class="language-bash">#  Select ST-Link v2 as SWD Programmer
swd_device=scripts/nrf52/swd-stlink.ocd
</code></pre>
<p>If we're using <a href="https://medium.com/@ly.lee/openocd-on-raspberry-pi-better-with-swd-on-spi-7dea9caeb590?source=friends_link&amp;sk=df399bfd913d3e262447d28aa5af6b63">Raspberry Pi SPI</a> for flashing PineTime, set <code>swd_device</code> as follows...</p>
<pre><code class="language-bash">#  Select Raspberry Pi as SWD Programmer
swd_device=scripts/nrf52-pi/swd-pi.ocd
</code></pre>
<h2 id="flash-mcuboot-bootloader" class="section-header"><a href="#flash-mcuboot-bootloader">12.7 Flash MCUBoot Bootloader</a></h2>
<ol>
<li>
<p>Download the <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot">MCUBoot Bootloader for PineTime</a>...</p>
<p><a href="https://github.com/lupyuen/pinetime-rust-mynewt/releases/download/v4.1.7/mynewt.elf.bin"><code>mynewt.elf.bin</code></a></p>
<p>For other versions of the bootloader, <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfutest">see this article</a></p>
</li>
<li>
<p>Edit <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/nrf52/flash-boot.sh"><code>~/pinetime/pinetime-rust-mynewt/scripts/nrf52/flash-boot.sh</code></a></p>
</li>
<li>
<p>Change <code>openocd/bin/openocd</code> to the path of our installed <code>openocd</code> (for ST-Link) or <code>openocd-spi</code> (for Raspberry Pi)...</p>
<pre><code class="language-bash">#  Flash the device
openocd/bin/openocd \
    -f $swd_device \
    -f scripts/nrf52/flash-boot.ocd
</code></pre>
</li>
<li>
<p>Edit <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/nrf52/flash-boot.ocd"><code>~/pinetime/pinetime-rust-mynewt/scripts/nrf52/flash-boot.ocd</code></a></p>
</li>
<li>
<p>Change <code>bin/targets/nrf52_boot/app/boot/mynewt/mynewt.elf.bin</code> to the path of the downloaded <code>mynewt.elf.bin</code></p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">program</span> <span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_boot</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">boot</span><span class="op">/</span><span class="ident">mynewt</span><span class="op">/</span><span class="ident">mynewt</span>.<span class="ident">elf</span>.<span class="ident">bin</span> <span class="ident">verify</span> <span class="number">0x00000000</span></pre></div>
</li>
<li>
<p>Flash the bootloader...</p>
<pre><code class="language-bash">scripts/nrf52/flash-boot.sh
</code></pre>
</li>
</ol>
<h2 id="flash-mynewt--micropython-firmware" class="section-header"><a href="#flash-mynewt--micropython-firmware">12.8 Flash Mynewt + MicroPython Firmware</a></h2>
<ol>
<li>
<p>Edit <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/nrf52/flash-app.sh"><code>~/pinetime/pinetime-rust-mynewt/scripts/nrf52/flash-app.sh</code></a></p>
</li>
<li>
<p>Change <code>openocd/bin/openocd</code> to the path of our installed <code>openocd</code> (for ST-Link) or <code>openocd-spi</code> (for Raspberry Pi)...</p>
<pre><code class="language-bash">#  Flash the device
openocd/bin/openocd \
    -f $swd_device \
    -f scripts/nrf52/flash-app.ocd
</code></pre>
</li>
<li>
<p>The path of the built firmware file is defined in <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/micropython/scripts/nrf52/flash-app.ocd"><code>~/pinetime/pinetime-rust-mynewt/scripts/nrf52/flash-app.ocd</code></a>. We shouldn't need to change this.</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">program</span> <span class="ident">bin</span><span class="op">/</span><span class="ident">targets</span><span class="op">/</span><span class="ident">nrf52_my_sensor</span><span class="op">/</span><span class="ident">app</span><span class="op">/</span><span class="ident">apps</span><span class="op">/</span><span class="ident">my_sensor_app</span><span class="op">/</span><span class="ident">my_sensor_app</span>.<span class="ident">img</span> <span class="ident">verify</span> <span class="number">0x00008000</span></pre></div>
</li>
<li>
<p>Flash the application...</p>
<pre><code class="language-bash">scripts/nrf52/flash-app.sh
</code></pre>
</li>
<li>
<p>PineTime reboots, starts wasp-os and renders the watch face</p>
</li>
</ol>
<p><img src="https://lupyuen.github.io/images/micropython-build.png" alt="Build Mynewt + MicroPython Firmware on Raspberry Pi" /></p>
<h1 id="debug-log" class="section-header"><a href="#debug-log">13 Debug Log</a></h1>
<p>Here's the debug log that appears in OpenOCD when we run <code>flash-app.sh</code>...</p>
<p>The firmware is flashed to PineTime via OpenOCD and ST-Link...</p>

<pre><code>&gt; Executing task in folder pinetime-rust-mynewt: bash -c -l &#39; scripts/nrf52/flash-app.sh &amp;&amp; echo ✅ ◾ ️Done! &#39; &lt;

+ source scripts/config.sh
++ swd_device=scripts/nrf52/swd-stlink.ocd
+ openocd/bin/openocd -f scripts/nrf52/swd-stlink.ocd -f scripts/nrf52/flash-app.ocd
GNU MCU Eclipse 64-bit Open On-Chip Debugger 0.10.0+dev-00462-gdd1d90111 (2019-01-15-13:49)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
adapter speed: 1000 kHz
force hard breakpoints
Stopping...
target halted due to debug-request, current mode: Thread 
xPSR: 0x61000000 pc: 0x000001c6 msp: 0x2000ffd8

Flashing Application...
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000
Enabled ARM Semihosting to show debug output
semihosting is enabled
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000001e msp: 0x20010000, semihosting
wrote 352256 bytes from file bin/targets/nrf52_my_sensor/app/apps/my_sensor_app/my_sensor_app.img in 8.465226s (40.637 KiB/s)
** Programming Finished **
** Verify Started **
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20010000, semihosting
verified 349048 bytes in 0.803118s (424.430 KiB/s)
** Verified OK **

Restarting...
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x000000d8 msp: 0x20010000, semihosting
Enabled ARM Semihosting to show debug output
semihosting is enabled
**** Done! Press Ctrl-C to exit...</code></pre>
<p>PineTime reboots after flashing. The MCUBoot Booloader starts...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">Starting</span> <span class="ident">Bootloader</span>...
<span class="ident">Displaying</span> <span class="ident">image</span>...
<span class="ident">Image</span> <span class="ident">displayed</span>
<span class="ident">Check</span> <span class="ident">button</span>: <span class="number">0</span>
[<span class="ident">INF</span>] <span class="ident">Primary</span> <span class="ident">image</span>: <span class="ident">magic</span><span class="op">=</span><span class="ident">good</span>, <span class="ident">swap_type</span><span class="op">=</span><span class="number">0x4</span>, <span class="ident">copy_done</span><span class="op">=</span><span class="number">0x1</span>, <span class="ident">image_ok</span><span class="op">=</span><span class="number">0x1</span>
[<span class="ident">INF</span>] <span class="ident">Scratch</span>: <span class="ident">magic</span><span class="op">=</span><span class="ident">bad</span>, <span class="ident">swap_type</span><span class="op">=</span><span class="number">0x1</span>, <span class="ident">copy_done</span><span class="op">=</span><span class="number">0x2</span>, <span class="ident">image_ok</span><span class="op">=</span><span class="number">0x2</span>
[<span class="ident">INF</span>] <span class="ident">Boot</span> <span class="ident">source</span>: <span class="ident">none</span>
[<span class="ident">INF</span>] <span class="ident">Swap</span> <span class="kw">type</span>: <span class="ident">none</span>
<span class="ident">Waiting</span> <span class="number">5</span> <span class="ident">seconds</span> <span class="kw">for</span> <span class="ident">button</span>: <span class="number">0</span>...
<span class="ident">Waited</span> <span class="kw">for</span> <span class="ident">button</span>: <span class="number">0</span>
<span class="ident">Bootloader</span> <span class="ident">done</span></pre></div>
<p>Mynewt starts running...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">TMP</span> <span class="ident">create</span> <span class="ident">temp_stub_0</span>
<span class="ident">NET</span> <span class="ident">hwid</span> <span class="number">4a</span> <span class="ident">f8</span> <span class="ident">cf</span> <span class="number">95</span> <span class="number">6a</span> <span class="ident">be</span> <span class="ident">c1</span> <span class="ident">f6</span> <span class="number">89</span> <span class="ident">ba</span> <span class="number">12</span> <span class="number">1a</span> 
<span class="ident">NET</span> <span class="ident">standalone</span> <span class="ident">node</span> </pre></div>
<p>MicroPython initialises the stack and heap...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">stack_start</span>: <span class="number">20000618</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">heap_start</span>: <span class="number">20004bfa</span>
<span class="ident">heap_end</span>: <span class="number">2000cbfa</span>
<span class="ident">TODO</span> <span class="ident">adc_init0</span>
<span class="ident">TODO</span> <span class="ident">timer_init0</span>
<span class="ident">TODO</span> <span class="ident">microbit_filesystem_init</span>
<span class="ident">TODO</span> <span class="ident">machine_rtc_make_new</span>
<span class="ident">TODO</span> <span class="ident">machine_rtc_start</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_make_new</span>
<span class="number">1</span> <span class="ident">chips</span> <span class="ident">detected</span>. <span class="ident">Total</span> <span class="ident">flash</span> <span class="ident">size</span> <span class="number">4MiB</span>.
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001dc0</span>, <span class="ident">len</span><span class="op">=</span><span class="number">216</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001f28</span>, <span class="ident">len</span><span class="op">=</span><span class="number">1bc</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span></pre></div>
<p>The ADC is probably used for reading the battery status.</p>
<p>wasp-os starts the REPL loop and renders the watch face...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">Watch</span> <span class="ident">is</span> <span class="ident">running</span>, <span class="kw">use</span> <span class="ident">Ctrl</span><span class="op">-</span><span class="ident">C</span> <span class="ident">to</span> <span class="ident">stop</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001f38</span>, <span class="ident">len</span><span class="op">=</span><span class="number">1b8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span></pre></div>
<p>After a while PineTime reboots, probably because of the Mynewt watchdog.</p>
<p>And PineTime runs the same thing again and again...</p>

<div class="example-wrap"><pre class="rust rust-example-rendered">
<span class="ident">Starting</span> <span class="ident">Bootloader</span>...
<span class="ident">Displaying</span> <span class="ident">image</span>...
<span class="ident">Image</span> <span class="ident">displayed</span>
<span class="ident">Check</span> <span class="ident">button</span>: <span class="number">0</span>
[<span class="ident">INF</span>] <span class="ident">Primary</span> <span class="ident">image</span>: <span class="ident">magic</span><span class="op">=</span><span class="ident">good</span>, <span class="ident">swap_type</span><span class="op">=</span><span class="number">0x4</span>, <span class="ident">copy_done</span><span class="op">=</span><span class="number">0x1</span>, <span class="ident">image_ok</span><span class="op">=</span><span class="number">0x1</span>
[<span class="ident">INF</span>] <span class="ident">Scratch</span>: <span class="ident">magic</span><span class="op">=</span><span class="ident">bad</span>, <span class="ident">swap_type</span><span class="op">=</span><span class="number">0x1</span>, <span class="ident">copy_done</span><span class="op">=</span><span class="number">0x2</span>, <span class="ident">image_ok</span><span class="op">=</span><span class="number">0x2</span>
[<span class="ident">INF</span>] <span class="ident">Boot</span> <span class="ident">source</span>: <span class="ident">none</span>
[<span class="ident">INF</span>] <span class="ident">Swap</span> <span class="kw">type</span>: <span class="ident">none</span>
<span class="ident">Waiting</span> <span class="number">5</span> <span class="ident">seconds</span> <span class="kw">for</span> <span class="ident">button</span>: <span class="number">0</span>...
<span class="ident">Waited</span> <span class="kw">for</span> <span class="ident">button</span>: <span class="number">0</span>
<span class="ident">Bootloader</span> <span class="ident">done</span>
<span class="ident">TMP</span> <span class="ident">create</span> <span class="ident">temp_stub_0</span>
<span class="ident">NET</span> <span class="ident">hwid</span> <span class="number">4a</span> <span class="ident">f8</span> <span class="ident">cf</span> <span class="number">95</span> <span class="number">6a</span> <span class="ident">be</span> <span class="ident">c1</span> <span class="ident">f6</span> <span class="number">89</span> <span class="ident">ba</span> <span class="number">12</span> <span class="number">1a</span> 
<span class="ident">NET</span> <span class="ident">standalone</span> <span class="ident">node</span> 
<span class="ident">stack_start</span>: <span class="number">20000618</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">heap_start</span>: <span class="number">20004bfa</span>
<span class="ident">heap_end</span>: <span class="number">2000cbfa</span>
<span class="ident">TODO</span> <span class="ident">adc_init0</span>
<span class="ident">TODO</span> <span class="ident">timer_init0</span>
<span class="ident">TODO</span> <span class="ident">microbit_filesystem_init</span>
<span class="ident">TODO</span> <span class="ident">machine_rtc_make_new</span>
<span class="ident">TODO</span> <span class="ident">machine_rtc_start</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_make_new</span>
<span class="number">1</span> <span class="ident">chips</span> <span class="ident">detected</span>. <span class="ident">Total</span> <span class="ident">flash</span> <span class="ident">size</span> <span class="number">4MiB</span>.
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001dc0</span>, <span class="ident">len</span><span class="op">=</span><span class="number">216</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001f28</span>, <span class="ident">len</span><span class="op">=</span><span class="number">1bc</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">Watch</span> <span class="ident">is</span> <span class="ident">running</span>, <span class="kw">use</span> <span class="ident">Ctrl</span><span class="op">-</span><span class="ident">C</span> <span class="ident">to</span> <span class="ident">stop</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">20001f38</span>, <span class="ident">len</span><span class="op">=</span><span class="number">1b8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span>
<span class="ident">TODO</span> <span class="ident">machine_adc_value_read</span>
<span class="ident">stack_end</span>: <span class="number">20002618</span>
<span class="ident">gc_collect</span>: <span class="ident">sp</span><span class="op">=</span><span class="number">200022b8</span>, <span class="ident">len</span><span class="op">=</span><span class="ident">d8</span></pre></div>
<h1 id="loose-ends" class="section-header"><a href="#loose-ends">14 Loose Ends</a></h1>
<p>This article is getting waaaaay too long, and I haven't covered all the topics yet. Drop me a note if you would like me to cover the following...</p>
<ol>
<li>
<p>VSCode Workspace for wasp-os and MicroPython: The Build Task for wasp-os and MicroPython is defined here: <a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/.vscode/tasks.json"><code>.vscode/tasks.json</code></a></p>
</li>
<li>
<p>Debugging wasp-os and MicroPython with VSCode and ST-Link</p>
</li>
<li>
<p>How debug messages from wasp-os and MicroPython are routed to OpenOCD's Semihosting Console (i.e. replacing <code>printf</code> by <code>console_printf</code>)</p>
</li>
<li>
<p>REPL Command Line: Will probably be implemented as a UART driver in MicroPython that talks to NimBLE</p>
</li>
<li>
<p>Supporting the other wasp-os drivers in <a href="https://github.com/lupyuen/wasp-os/tree/master/wasp/drivers"><code>wasp-os/wasp/drivers</code></a>: SPI Flash, Battery, nRF Real Time Clock, Signal, Vibrator</p>
</li>
</ol>
<h1 id="whats-next" class="section-header"><a href="#whats-next">15 What's Next</a></h1>
<p><em>Will we see wasp-os and MicroPython run on Mynewt someday?</em></p>
<p>The work continues! We have a showstopper: Unable to handle Bluetooth packets due to conflicts with the Mynewt and the MicroPython task scheduler.</p>
<p>I'll continue to experiment on wasp-os with <a href="https://forum.pine64.org/showthread.php?tid=9017&amp;page=4">guidance</a> from <a href="https://github.com/daniel-thompson">Daniel</a> and keep this article updated!</p>
<h1 id="further-reading" class="section-header"><a href="#further-reading">16 Further Reading</a></h1>
<p><a href="https://wasp-os.readthedocs.io/en/latest/">wasp-os documentation</a></p>
<p><a href="https://wasp-os.readthedocs.io/en/latest/appguide.html">wasp-os Application Writer’s Guide</a></p>
<p><a href="https://wasp-os.readthedocs.io/en/latest/wasp.html">wasp-os Reference Manual</a></p>
<p><em><a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot">&quot;MCUBoot Bootloader for PineTime Smart Watch (nRF52)&quot;</a></em></p>
<p><em><a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfu">&quot;Firmware Update over Bluetooth Low Energy on PineTime Smart Watch&quot;</a></em></p>
<p><em><a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfutest">&quot;Wireless Firmware Update In Action on PineTime Smart Watch (nRF52)&quot;</a></em></p>
<p><a href="https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/README.md">Check out the other PineTime articles</a></p>
<p><a href="https://lupyuen.github.io/rss.xml">RSS Feed</a></p>

    
</body>
</html>